package com.springboot.utils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Service;

import java.io.Serializable;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * Redis工具类
 * 提供常用的Redis操作方法，包括字符串、哈希、列表、集合、有序集合等数据类型的操作
 * 
 * @Service 注解标识这是一个服务类
 */
@Service
public class RedisUtils {
    
    /**
     * Redis模板，用于执行Redis操作
     */
    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 布隆过滤器大小，2的32次方
     */
    private static double size = Math.pow(2, 32);


    /**
     * 设置位图值
     *
     * @param key Redis键
     * @param offset 位偏移量 (8Bit=1Byte)
     * @param isShow 要设置的值(true/false)
     * @return 设置是否成功
     */
    public boolean setBit(String key, long offset, boolean isShow) {
        boolean result = false;
        try {
            ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
            operations.setBit(key, offset, isShow);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 获取位图值
     *
     * @param key Redis键
     * @param offset 位偏移量
     * @return 位图值
     */
    public boolean getBit(String key, long offset) {
        boolean result = false;
        try {
            ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
            result = operations.getBit(key, offset);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 设置缓存值
     *
     * @param key Redis键
     * @param value 要缓存的值
     * @return 设置是否成功
     */
    public boolean set(final String key, Object value) {
        boolean result = false;
        try {
            ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
            operations.set(key, value);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 设置带过期时间的缓存值
     *
     * @param key Redis键
     * @param value 要缓存的值
     * @param expireTime 过期时间(秒)
     * @return 设置是否成功
     */
    public boolean set(final String key, Object value, Long expireTime) {
        boolean result = false;
        try {
            ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
            operations.set(key, value);
            redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 批量删除缓存
     *
     * @param keys 要删除的键数组
     */
    public void remove(final String... keys) {
        for (String key : keys) {
            remove(key);
        }
    }

    /**
     * 删除单个缓存
     *
     * @param key 要删除的键
     */
    public void remove(final String key) {
        if (exists(key)) {
            redisTemplate.delete(key);
        }
    }

    /**
     * 判断键是否存在
     *
     * @param key Redis键
     * @return 是否存在
     */
    public boolean exists(final String key) {
        return redisTemplate.hasKey(key);
    }

    /**
     * 获取缓存值
     *
     * @param key Redis键
     * @return 缓存的值
     */
    public Object get(final String key) {
        Object result = null;
        ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
        result = operations.get(key);
        return result;
    }

    /**
     * 设置哈希值
     *
     * @param key Redis键
     * @param hashKey 哈希键
     * @param value 哈希值
     */
    public void hmSet(String key, Object hashKey, Object value) {
        HashOperations<String, Object, Object> hash = redisTemplate.opsForHash();
        hash.put(key, hashKey, value);
    }

    /**
     * 获取哈希值
     *
     * @param key Redis键
     * @param hashKey 哈希键
     * @return 哈希值
     */
    public Object hmGet(String key, Object hashKey) {
        HashOperations<String, Object, Object> hash = redisTemplate.opsForHash();
        return hash.get(key, hashKey);
    }

    /**
     * 向列表右侧添加元素
     *
     * @param k 列表键
     * @param v 要添加的值
     */
    public void lPush(String k, Object v) {
        ListOperations<String, Object> list = redisTemplate.opsForList();
        list.rightPush(k, v);
    }

    /**
     * 获取列表范围元素
     *
     * @param k 列表键
     * @param l 起始索引
     * @param l1 结束索引
     * @return 列表元素
     */
    public List<Object> lRange(String k, long l, long l1) {
        ListOperations<String, Object> list = redisTemplate.opsForList();
        return list.range(k, l, l1);
    }

    /**
     * 向集合添加元素
     *
     * @param key 集合键
     * @param value 要添加的值
     */
    public void add(String key, Object value) {
        SetOperations<String, Object> set = redisTemplate.opsForSet();
        set.add(key, value);
    }

    /**
     * 获取集合所有成员
     *
     * @param key 集合键
     * @return 集合成员
     */
    public Set<Object> setMembers(String key) {
        SetOperations<String, Object> set = redisTemplate.opsForSet();
        return set.members(key);
    }

    /**
     * 向有序集合添加元素
     *
     * @param key 有序集合键
     * @param value 元素值
     * @param scoure 分数
     */
    public void zAdd(String key, Object value, double scoure) {
        ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
        zset.add(key, value, scoure);
    }

    /**
     * 根据分数范围获取有序集合元素
     *
     * @param key 有序集合键
     * @param scoure 最小分数
     * @param scoure1 最大分数
     * @return 有序集合元素
     */
    public Set<Object> rangeByScore(String key, double scoure, double scoure1) {
        ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
        redisTemplate.opsForValue();
        return zset.rangeByScore(key, scoure, scoure1);
    }

    /**
     * 保存数据到Redis布隆过滤器
     * 第一次加载的时候将数据加载到redis中
     *
     * @param name 要保存的名称
     */
    public void saveDataToRedis(String name) {
        double index = Math.abs(name.hashCode() % size);
        long indexLong = new Double(index).longValue();
        boolean availableUsers = setBit("availableUsers", indexLong, true);
    }

    /**
     * 从Redis布隆过滤器获取数据
     * 检查数据是否存在于布隆过滤器中
     *
     * @param name 要检查的名称
     * @return 是否存在
     */
    public boolean getDataToRedis(String name) {
        double index = Math.abs(name.hashCode() % size);
        long indexLong = new Double(index).longValue();
        return getBit("availableUsers", indexLong);
    }

    /**
     * 获取有序集合元素排名
     *
     * @param key 有序集合键
     * @param value 元素值
     * @return 元素排名
     */
    public Long zRank(String key, Object value) {
        ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
        return zset.rank(key,value);
    }

    /**
     * 获取有序集合元素排名（带分数）
     *
     * @param key 有序集合键
     * @param start 起始排名
     * @param end 结束排名
     * @return 带分数的元素集合
     */
    public Set<ZSetOperations.TypedTuple<Object>> zRankWithScore(String key, long start,long end) {
        ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
        Set<ZSetOperations.TypedTuple<Object>> ret = zset.rangeWithScores(key,start,end);
        return ret;
    }

    /**
     * 获取有序集合元素分数
     *
     * @param key 有序集合键
     * @param value 元素值
     * @return 元素分数
     */
    public Double zSetScore(String key, Object value) {
        ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
        return zset.score(key,value);
    }

    /**
     * 增加有序集合元素分数
     *
     * @param key 有序集合键
     * @param value 元素值
     * @param scoure 要增加的分数
     */
    public void incrementScore(String key, Object value, double scoure) {
        ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
        zset.incrementScore(key, value, scoure);
    }

    /**
     * 获取有序集合元素反向排名（带分数，按分数从高到低）
     *
     * @param key 有序集合键
     * @param start 起始排名
     * @param end 结束排名
     * @return 带分数的元素集合
     */
    public Set<ZSetOperations.TypedTuple<Object>> reverseZRankWithScore(String key, long start,long end) {
        ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
        Set<ZSetOperations.TypedTuple<Object>> ret = zset.reverseRangeByScoreWithScores(key,start,end);
        return ret;
    }

    /**
     * 获取有序集合元素反向排名（带排名，按分数从高到低）
     *
     * @param key 有序集合键
     * @param start 起始排名
     * @param end 结束排名
     * @return 带分数的元素集合
     */
    public Set<ZSetOperations.TypedTuple<Object>> reverseZRankWithRank(String key, long start, long end) {
        ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
        Set<ZSetOperations.TypedTuple<Object>> ret = zset.reverseRangeWithScores(key, start, end);
        return ret;
    }
}
